package com.ssy.lingxi.pay.serviceimpl;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.constant.order.OrderPaymentParameterEnum;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.pay.model.dto.ParameterCacheDTO;
import com.ssy.lingxi.pay.service.IPayCacheService;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 订单缓存接口实现类
 * @author 万宁
 * @version 2.0.0
 * @date 2021-08-20
 */
@Service
public class PayCacheServiceImpl implements IPayCacheService {
    private static final Logger logger = LoggerFactory.getLogger(PayCacheServiceImpl.class);

    @Resource
    private IRedisStringUtils redisStringUtils;

    /**
     * 缓存24小时
     */
    private static final long cacheTimeOutSeconds = 24 * 60 * 60;

    /**
     * 缓存Key的前缀
     */
    private static final String cachePrefix = "pay:";

    /**
     * 生成随机字符串
     *
     * @return 随机字符串
     */
    @Override
    public String randomString() {
        String chars = "abcdefghijklmnopqrstuvwxyz1234567890";
        return RandomStringUtils.random(8, chars);
    }

    /**
     * Json序列化对象
     *
     * @param obj 对象
     * @return Json字符串
     */
    @Override
    public String serializeObject(Object obj) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            return mapper.writeValueAsString(obj);
        } catch (Exception e) {
            logger.error("序列化对象错误：" + e.getMessage());
            return "";
        }
    }

    /**
     * 反序列化对象
     *
     * @param json   Json字符串
     * @param tClass 反序列化对象的Class
     * @return 对象
     */
    @Override
    public <T> T deserializeObject(String json, Class<T> tClass) {
        try {
            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return mapper.readValue(json, tClass);
        } catch (Exception e) {
            logger.error("反序列化对象错误：" + e.getMessage());
            return null;
        }
    }

    /**
     * 生成微信支付参数缓存列表
     *
     * @param merchantId 微信商户号
     * @param appId      AppId
     * @param apiKey     ApiKey
     * @return 缓存参数列表
     */
    @Override
    public List<ParameterCacheDTO> generateWeChatPayParameters(String merchantId, String appId, String apiKey) {
        return Stream.of(OrderPaymentParameterEnum.WECHAT_MERCHANT_ID, OrderPaymentParameterEnum.WECHAT_APP_ID, OrderPaymentParameterEnum.WECHAT_API_KEY).map(p -> {
            ParameterCacheDTO cacheDTO = new ParameterCacheDTO();
            cacheDTO.setCode(p.getCode());
            switch (p) {
                case WECHAT_MERCHANT_ID:
                    cacheDTO.setValue(merchantId);
                    break;
                case WECHAT_APP_ID:
                    cacheDTO.setValue(appId);
                    break;
                case WECHAT_API_KEY:
                    cacheDTO.setValue(apiKey);
                    break;
                default:
                    cacheDTO.setValue("");
                    break;
            }
            return cacheDTO;
        }).collect(Collectors.toList());
    }

    /**
     * 缓存微信支付参数
     *
     * @param memberId   会员Id
     * @param roleId     角色Id
     * @param payType    支付类型
     * @param nonce      随机字符串
     * @param merchantId 微信商户号
     * @param appId      AppId
     * @param apiKey     ApiKey
     */
    @Override
    public void cacheWeChatPayParameters(Long memberId, Long roleId, Integer payType, String nonce, String merchantId, String appId, String apiKey) {
        cachePayParameters(memberId, roleId, payType, nonce, generateWeChatPayParameters(merchantId, appId, apiKey));
    }

    /**
     * 缓存订单支付参数
     *
     * @param memberId   会员Id
     * @param roleId     角色Id
     * @param payType    支付类型
     * @param nonce   随机字符串
     * @param parameters 要缓存的支付参数
     */
    @Override
    public void  cachePayParameters(Long memberId, Long roleId, Integer payType, String nonce, List<ParameterCacheDTO> parameters) {
        try {
            final String key = cachePrefix.concat(String.valueOf(memberId)).concat(":").concat(String.valueOf(roleId)).concat(":").concat(String.valueOf(payType)).concat(":").concat(nonce);
            ObjectMapper mapper = new ObjectMapper();
            String jsonValue = mapper.writeValueAsString(parameters);
            Boolean cacheSuccess = redisStringUtils.set(key, jsonValue, cacheTimeOutSeconds, Constants.REDIS_PAY_INDEX);
            logger.info("缓存订单支付参数, memberId:" + memberId + ", roleId: " + roleId + ", payType: " + payType + ", nonce:" + nonce + ", parameters:" + jsonValue + ", 缓存结果: " + cacheSuccess);
        } catch (Exception e) {
            logger.error("缓存订单支付参数错误：" + e.getMessage());
        }
    }

    /**
     * 查询缓存的订单支付参数
     *
     * @param memberId 会员Id
     * @param roleId   角色Id
     * @param payType  支付类型
     * @param nonce 随机字符串
     * @return 缓存的支付参数
     */
    @Override
    public List<ParameterCacheDTO> findPayParameters(Long memberId, Long roleId, Integer payType, String nonce) {
        try {
            final String key = cachePrefix.concat(String.valueOf(memberId)).concat(":").concat(String.valueOf(roleId)).concat(":").concat(String.valueOf(payType)).concat(":").concat(nonce);
            String jsonValue = redisStringUtils.get(key, Constants.REDIS_PAY_INDEX);

            logger.info("查询缓存支付参数：memberId: " + memberId + ", roleId:" + roleId + ", payType:" + payType + ", nonce:" + nonce + ", 查询结果: " + jsonValue);

            ObjectMapper mapper = new ObjectMapper();
            mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
            return mapper.readValue(jsonValue, new TypeReference<List<ParameterCacheDTO>>() {});
        } catch (Exception e) {
            logger.error("读取缓存的支付参数错误：" + e.getMessage());
            return new ArrayList<>();
        }
    }

    /**
     * 缓存支付宝支付参数
     * @param memberId 会员Id
     * @param memberRoleId   角色Id
     * @param payType  支付类型
     * @param nonce  随机字符串
     * @param appId      支付宝AppId
     * @param alipayPublicKey 支付宝公钥
     * @param appPrivateKey 支付宝商户私钥
     */

    @Override
    public void cacheAliPayParameters(Long memberId, Long memberRoleId, Integer payType, String nonce, String appId,String alipayPublicKey, String appPrivateKey) {
        cachePayParameters(memberId, memberRoleId, payType, nonce, generateAliPayParameters(appId,alipayPublicKey,appPrivateKey));
    }

    /**
     * 生成支付宝支付参数缓存列表
     * @param appId
     * @param alipayPublicKey
     * @param appPrivateKey
     * @return
     */
    private List<ParameterCacheDTO> generateAliPayParameters(String appId,String alipayPublicKey, String appPrivateKey) {
        return Stream.of(OrderPaymentParameterEnum.ALIPAY_APP_ID, OrderPaymentParameterEnum.ALIPAY_PUBLIC_KEY,OrderPaymentParameterEnum.APP_ALIPAY_PRIVATE_KEY).map(p -> {
            ParameterCacheDTO cacheDTO = new ParameterCacheDTO();
            cacheDTO.setCode(p.getCode());
            switch (p) {
                case ALIPAY_APP_ID:
                    cacheDTO.setValue(appId);
                    break;
                case ALIPAY_PUBLIC_KEY:
                    cacheDTO.setValue(alipayPublicKey);
                    break;
                case APP_ALIPAY_PRIVATE_KEY:
                    cacheDTO.setValue(appPrivateKey);
                    break;
                default:
                    cacheDTO.setValue("");
                    break;
            }
            return cacheDTO;
        }).collect(Collectors.toList());
    }
}
